package org.rjxh.examfront.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.rjxh.examfront.mapper.ExamQuestionMapper;
import org.rjxh.examfront.mapper.ExamRecordMapper;
import org.rjxh.examfront.mapper.ExamRespondMapper;
import org.rjxh.examfront.mapper.ExamRoleMapper;
import org.rjxh.examfront.pojo.*;
import org.rjxh.examfront.service.*;
import org.rjxh.examfront.web.tools.RedisCache;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import springfox.documentation.spring.web.json.Json;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 考试记录 服务实现类
 * </p>
 *
 * @author BA7LGJ
 * @since 2024-04-04
 */
@Service
public class ExamRecordServiceImpl extends ServiceImpl<ExamRecordMapper, ExamRecord> implements IExamRecordService {
    @Resource
    private ExamRecordMapper examRecordMapper;

    @Resource
    private ExamRespondMapper examRespondMapper;

    @Resource
    private IExamRespondService examRespondService;

    @Resource
    private ExamQuestionMapper examQuestionMapper;

    @Resource
    private ICodeRunService codeRunService;


    @Resource
    private ExamRoleMapper examRoleMapper;

    @Resource
    private IExamQuestionService examQuestionService;

    @Resource
    private IExamExaminationService examExaminationService;
    @Resource
    private RedisCache redisCache;

    public R selectExamRankingsByExamId(Long examId) {
        return new R(200, "success", examRecordMapper.selectExamRankingsByExamId(examId));
    }

    @Override
    public R finishExam() {

        LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        Long recordId = redisCache.getCacheObject("examRecordingUser:" + loginUser.getUser().getUserId());
        if (recordId == null) {
            return new R<>(500, "当前用户没有正在进行的考试！");
        }

        //获得用户回答用于计算分数+存数据库
        Map<String, ExamRespond> examRespondsMap = redisCache.getCacheMap("RecordResponds:" + recordId);
        examRespondService.saveBatch(examRespondsMap.values());
        if (!redisCache.deleteObject("RecordResponds:" + recordId)) {
            return new R<>(500, "考试结束失败！");
        }

        // 删除redis缓存
        boolean b = redisCache.deleteObject("examRecordingUser:" + loginUser.getUser().getUserId());
        if (!b) {
            return new R<>(500, "考试结束失败！");
        }

        ExamRecord examRecord = redisCache.getCacheObject("examRecording:" + recordId);
        boolean b1 = redisCache.deleteObject("examRecording:" + recordId);
        if (!b1) {
            return new R<>(500, "考试结束失败！");
        }

        // 计算用户考试时长
        LocalDateTime startTime = examRecord.getExamStartTime();
        Duration duration = Duration.between(startTime, LocalDateTime.now());
        long seconds = duration.getSeconds();

        // 计算理论成绩

        //这坨 key为QuestionId value为ExamQuestion 每个ExamQuestion都包含的正确答案
        Map<Long, ExamQuestion> examQuestions = examQuestionMapper.selectQuestionIncludeAnswer(examRecord.getExamExamination().getExamId())
                .stream()
                    .collect(
                            Collectors.toMap(
                                    ExamQuestion::getQuestionId,
                                    examQuestion -> examQuestion,
                                    (oldValue, newValue) -> oldValue
                            )
                    );


        //Map<Long, ExamRespond> examResponds = examRespondMapper.selectList(new LambdaQueryWrapper<ExamRespond>().eq(ExamRespond::getRecordId, recordId))
        //        .stream()
        //        .collect(
        //                Collectors.toMap(
        //                        ExamRespond::getQuestionId,
        //                        examRespond -> examRespond,
        //                        (oldValue, newValue) -> oldValue
        //                )
        //        );


        int logicScore = calculateScore(examQuestions,examRespondsMap);
        // 写入更新的历史值

        examRecord.setDuration((int) seconds).setLogicScore(new BigDecimal(logicScore));
        boolean b2 = this.updateById(examRecord);
        if (b2) {
            return new R<>(200, "考试结束成功！");
        }

        return new R<>(500, "考试结束失败！");

    }

    @Override
    public R selectRecordDetailByRecordId(Long recordId) {
        LoginUser loginUser = (LoginUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        Long userId = loginUser.getUser().getUserId();

        boolean access = checkAuthentication(userId, recordId);
        if (!access){
            return new R<>(500, "没有权限查看！");
        }



        ExamExamination examExaminationDTO = examExaminationService.getExaminationByRecordID(recordId);

        // 获得考试记录
        ExamRecord examRecord = examRecordMapper.selectOne(new LambdaQueryWrapper<ExamRecord>().eq(ExamRecord::getRecordId, recordId));
        //key是questionId
        Map<Long, ExamRespond> examRespondsMap = examRespondService.list(new LambdaQueryWrapper<ExamRespond>().eq(ExamRespond::getRecordId, recordId))
                .stream().collect(Collectors.toMap(
                        ExamRespond::getQuestionId,
                        examRespond -> examRespond,
                        (oldValue, newValue) -> oldValue
                ));

        examExaminationDTO.setExamRecord(examRecord);

        // 获得考试问题 并放入考试对象
        examExaminationDTO.setExamQuestionList(examQuestionMapper.selectQuestionsByExamId(new Page<ExamQuestion>().setSize(-1),examExaminationDTO.getExamId()).getRecords());

        //给每个考试问题塞入学生的回答
        List<ExamQuestion> examQuestionList = examExaminationDTO.getExamQuestionList();
        if (examQuestionList!=null){
            for (ExamQuestion examQuestion : examQuestionList) {
                examQuestion.setExamRespond(examRespondsMap.get(examQuestion.getQuestionId()));
            }
        }

        return new R(200, "操作成功", examExaminationDTO);
    }

    /**
     * 检查用户是否有权限查看这个recordId 的内容
     * @param userId
     * @param recordId
     * @return
     */
    private boolean checkAuthentication(Long userId, Long recordId) {
        //查询用户角色
        List<String> roleKeys = examRoleMapper.selectPermsByUserId(userId);
        for (String roleKey : roleKeys){
            if (roleKey.equals("teacher")){
                return true;
            }
        }

        ExamRecord examRecord = examRecordMapper.selectOne(new LambdaQueryWrapper<ExamRecord>().eq(ExamRecord::getRecordId, recordId));
        if(examRecord!=null && examRecord.getExamUserId().equals(userId)){
            return true;
        }

        return false;
    }


    //todo 临时的解决方案，判断正确的数量
    private int calculateScore(Map<Long, ExamQuestion> examQuestions, Map<String, ExamRespond> examResponds) {
        //都不为空 才能判断
        if (!examQuestions.isEmpty() && !examResponds.isEmpty()) {
            int score = 0;
            Set<String> questionIdsByExamResponds = examResponds.keySet();
            for (String questionIdByExamRespondKeyString : questionIdsByExamResponds) {
                long questionIdByExamResponds = Long.parseLong(questionIdByExamRespondKeyString);


                ExamQuestion examQuestion = examQuestions.get(questionIdByExamResponds);
                if (examQuestion == null){
                    //todo 用户答非所问，回答了一个不存在的问题
                    continue;
                }
                ExamRespond examRespond = examResponds.get(questionIdByExamRespondKeyString);


                String type = examQuestion.getQuestionType();
                //type只有一个字符
                //todo m代表多选题 未做多选题的判断
                //todo g代表填空题 未做多选题的判断
                //s代表单选，t判断,
                switch (type) {
                    case "t":
                    case "s":
                        String respond = examRespond.getRespond();
                        String answer = examQuestion.getExamAnswers().get(0).getAnswerId().toString();
                        if (respond.equals(answer)) {
                            score += 5;
                        }
                        break;
                    //case "m":
                    //    String[] split = examRespond.getRespond().split(",");
                    //    for (String s : split) {
                    //        if (examQuestion.getAnswer().contains(s)) {
                    //            score += 5;
                    //        }
                    //    }
                    //    break;
                    //case "g":
                    //    String[] split = examRespond.getRespond().split(",");
                    //    for (String s : split) {
                    //        if (examQuestion.getAnswer().contains(s)) {
                    //            score += 5;
                    //        }
                    //    }
                    //break;
                    case "c":
                        //代码题
                        String respondCode = examRespond.getRespondDesc();

                        if (StringUtils.isEmpty(respondCode)) {
                            continue;
                        }

                        List<ExamAnswer> examAnswers = examQuestion.getExamAnswers();
                        for (ExamAnswer examAnswer : examAnswers) {
                            HashMap<String,String> codeExamplesMap = JSON.parseObject(examAnswer.getAnswerContent(), HashMap.class);
                            Set<String> codeExamples = codeExamplesMap.keySet();
                            for (String codeExample : codeExamples) {
                                R<?> result = codeRunService.codeRun(new CodeRequest(respondCode, "c", codeExample,examQuestion.getQuestionId()));
                                if (result!=null && result.getCode() == 200){
                                    CodeRespond codeRespond = (CodeRespond) result.getData();
                                    if (codeRespond.getReturnCode()==0 && codeRespond.getStdout().equals(codeExamplesMap.get(codeExample))) {
                                        score += 10;
                                    }
                                }
                            }
                        }
                        break;
                }
            }
            return score;
        }
        //    某个为空，直接返回0
        return 0;
    }
}
